Skip to content

Remove Montana property tax rebate from non-refundable credit list - #9348

Open
DTrim99 wants to merge 3 commits into
PolicyEngine:mainfrom
DTrim99:fix/mt-property-tax-rebate
Open

Remove Montana property tax rebate from non-refundable credit list#9348
DTrim99 wants to merge 3 commits into
PolicyEngine:mainfrom
DTrim99:fix/mt-property-tax-rebate

Conversation

@DTrim99

@DTrim99 DTrim99 commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

The Montana Property Tax Rebate (up to $675 for TY2022 and TY2023) is a standalone rebate — homeowners claim it on a separate application to the Department of Revenue (tap.dor.mt.gov, window Aug 15 – Oct 1, 2024 for TY2023). It is not a Form 2 nonrefundable income-tax credit and does not reduce income tax liability.

It was listed in gov.states.mt.tax.income.credits.non_refundable (the 2022-01-01 entry), so mt_income_tax_before_refundable_credits_joint subtracted it. Two compounding defects:

  1. Misclassification — a standalone direct-payment rebate booked as a Form 2 line-19 credit.
  2. Household multiplicationmt_non_refundable_credits is a Person variable that adds the list; mt_property_tax_rebate is a TaxUnit variable ($675), so PolicyEngine projected it onto every member of the tax unit ($675 × 3 = $2,025 for a family of three).

Net effect: Montana income tax understated by $675 per household member.

Change

Remove mt_property_tax_rebate from the 2022-01-01 credit list, leaving [mt_capital_gain_credit]. The rebate variable still computes its $675 value — it simply no longer reduces income tax. (The 2024-01-01: [] entry already drops it thereafter; mt_income_tax_rebate in the 2021 entry is untouched, as the emulator's srebate mechanism relies on it.)

Testing

Verified on the issue household (MT joint 2023, ages 26/25, 1 dependent, $114,039 wages, $204 interest, $2,755 property tax): mt_non_refundable_credits goes from [675, 675, 675][0, 0, 0] and mt_income_tax from 3,683.16 → 5,708.16, matching the TaxAct Form 2 (line 18 = line 20 = $5,708, credit schedule blank). Added a regression test to the Montana integration suite.

Found via PolicyEngine-TAXSIM discrepancy #1152 (and its 2022 counterpart #1150), reported by @feenberg.

Sibling of #8970 (@PavelMakarchuk), which scopes the Montana income tax rebate — same subsystem, different rebate, no file overlap.

Fixes #9347.

🤖 Generated with Claude Code

The Montana Property Tax Rebate (up to $675 for TY2022-2023) is a standalone
rebate claimed on a separate application to the Department of Revenue, not a
Form 2 nonrefundable income-tax credit. It was listed in
gov.states.mt.tax.income.credits.non_refundable, so it reduced Montana income
tax; and because the person-level aggregator mt_non_refundable_credits adds the
tax-unit-level $675 rebate, PolicyEngine projected it onto every household
member (e.g. $675 x 3 = $2,025 for a family of three), understating MT tax.

Remove it from the 2022-01-01 credit list, leaving mt_capital_gain_credit. The
rebate variable still computes its $675 value; it simply no longer reduces
income tax. Restores mt_income_tax to 5,708.16 for the issue household (was
3,683.16), matching the TaxAct return.

Fixes PolicyEngine#9347.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ECQhxDkVchXm1RNVyqwnx
@DTrim99
DTrim99 requested a review from PavelMakarchuk August 26, 2026 18:21

@PavelMakarchuk PavelMakarchuk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 9348 — Consolidated review report

"Remove Montana property tax rebate from non-refundable credit list" — DTrim99 (fixes #9347; found via TAXSIM discrepancies policyengine-taxsim#1150/#1152)

Source Documents

  • Reviewed head SHA: 3066fdce840330ef55ddab14dab4e30046e9fd4f
  • Mode: full (delegate roles: regulatory [with pdf-collector/audit folded in], references, code-pattern, tests, verification-planner)
  • Snapshot: /tmp/policyengine-command-runs/2b3d452ec8fd/pr9348-pr-snapshot
  • Role reports: pr9348-review-context.md, pr9348-review-regulatory.md, pr9348-review-references.md, pr9348-review-code.md, pr9348-review-tests.md, pr9348-review-verification-queue.md (all under RUN_ROOT)
  • Archived primary sources (Wayback, byte-identical to originals): pr9348-mt-form2-2022-instructions.pdf (1,403,508 B), pr9348-mt-form2-2023-instructions.pdf (1,412,574 B)

Branch Status

  • BEHIND=0, AHEAD=2 — current with main, no rebase needed.
  • CI: all 31 checks pass.
  • Diff (63 lines, 3 files): policyengine_us/parameters/gov/states/mt/tax/income/credits/non_refundable.yaml (removes mt_property_tax_rebate from the 2022-01-01 list), policyengine_us/tests/policy/baseline/gov/states/mt/tax/income/integration.yaml (1 new case), changelog.d/mt-property-tax-rebate.fixed.md.

Verified substance (why the removal is correct)

The core claim is source-confirmed against both years' primary documents:

  1. Not a Form 2 credit. The 2023 MT Form 2 Instructions (archived copy, PDF p.5) describe the Property Tax Rebate (HB 222/HB 816, TY2022–2023, lesser of property tax paid or $675) as claimed separately via the TransAction Portal or Form MPTR23 in fixed claim windows, and state the rebate "is exempt from Montana income tax" — it sits entirely outside the income tax calculation. The complete Nonrefundable Credits Schedules for both TY2022 (PDF p.16, pp.43–44) and TY2023 (PDF p.18, pp.46–49) were enumerated line by line: the Property Tax Rebate appears in neither. The 2022 instructions (published Dec 2022, pre-HB 222) never mention it at all.
  2. Tripling mechanism confirmed in code. mt_non_refundable_credits is a Person-entity variable with a parameter adds list; mt_property_tax_rebate is TaxUnit-entity. policyengine-core projects the tax-unit value onto every member in a Person-level adds, so a 3-member household carried 3 × $675 = $2,025 of phantom credit (verified in core map_to/project semantics).
  3. Arithmetic re-derived exactly. Issue-9347 household (MT joint, 2023): tax before non-refundable credits $5,708.16; pre-fix $3,683.16 = 5,708.16 − 2,025; post-fix $5,708.16, matching the PR body's TaxAct verification. Both new test assertions (mt_property_tax_rebate: 675, mt_non_refundable_credits: [0, 0, 0]) were independently hand re-derived, and the case is confirmed discriminating (pre-PR code yields [675, 675, 675]).
  4. No collateral damage. mt_property_tax_rebate is not orphaned (still consumed via gov.states.household.state_property_tax_creditstaxsim_state_property_tax_credit, plus its own unit test). The remaining list entries — mt_capital_gain_credit (2021/2022) and mt_income_tax_rebate (2021) — are both Person-entity, so no analogous projection defect remains in this list.

Critical

None in this PR's diff. The one-line parameter change is source-confirmed correct for both affected years, the regression test is sound and discriminating, and CI is green.

Disposition note on the references role's C1 (dead 2022 href): the mtrevenue.gov links were dead before this PR (MT DOR site migration; this PR adds no hrefs), the cited content was successfully retrieved and corroborated from archived and live-mirror copies, and verified replacement URLs exist. Per the pre-existing-issue discipline it does not block; it is carried as A1 below because the file is being edited anyway.

Pre-existing findings (outside this diff — follow-up issue material)

The code role's repo-wide entity-projection sweep (6,040 variables AST-parsed; 817 adds lists resolved) found 8 live instances of the same bug class this PR fixes — a Person-entity adds list containing a group-entity variable whose projected value is then summed or subtracted per person. All 8 pre-date this PR, none is touched by its diff, and per canonical rules none blocks it. Recommend opening a tracking issue (one umbrella or eight singles) citing verified core semantics: group→person adds projects the FULL group value onto each member.

# Person-entity variable (file) Offending group-entity entry Consumer / mechanism
P1 policyengine_us/variables/gov/states/mt/tax/income/deductions/itemized/general/mt_misc_deductions.py casualty_loss_deduction [TaxUnit] mt_itemized_deductions_joint.py:24 sums per member (× household size); mt_itemized_deductions_indiv.py:29 doubles on separate-on-same-return. Same MT subsystem as this PR.
P2 policyengine_us/variables/gov/local/ca/la/general_relief/la_general_relief_gross_income.py tanf [SPMUnit] la_general_relief_net_income.py:16 — TANF counted once per member; exact analogue of #9347
P3 policyengine_us/variables/gov/states/ms/tax/income/ms_agi_adjustments.py self_employed_health_insurance_ald, health_savings_account_ald, self_employed_pension_contribution_ald [TaxUnit] ms_agi.py:20 subtracts full unit ALD from each non-dependent → double-counted for couples
P4 policyengine_us/variables/gov/states/oh/tax/income/deductions/medical_exepenses/oh_unreimbursed_medical_care_expense_deduction_person.py oh_insured_unreimbursed_medical_care_expenses [TaxUnit] oh_unreimbursed_medical_care_expense_deduction.py sums members → × member count
P5 policyengine_us/variables/gov/states/wv/tax/income/subtractions/senior_citizen_disability/wv_senior_citizen_disability_deduction_total_modifications.py us_govt_interest [TaxUnit] wv_senior_citizen_disability_deduction_person.py:22 — deduction understated for couples
P6 policyengine_us/variables/gov/local/ca/riv/general_relief/income/earned/ca_riv_general_relief_earned_income_deductions.py state_withheld_income_tax, additional_medicare_tax [TaxUnit] ca_riv_general_relief_net_earned_income.py — deductions double-counted per earner
P7 policyengine_us/variables/gov/local/ca/riv/general_relief/property/ca_riv_general_relief_countable_property_value.py spm_unit_cash_assets, ca_riv_general_relief_countable_vehicle_value [SPMUnit] ca_riv_general_relief_property_eligible.py:14 auto-sums members → assets × member count → wrongly fails eligibility
P8 policyengine_us/variables/gov/states/il/dhs/aabd/income/expense/il_aabd_expense_exemption_person.py state_withheld_income_tax [TaxUnit] il_aabd_earned_income_after_exemption_person.py:17 — exemption double-counted for couples

Additional pre-existing follow-ups (should-address grade, outside this diff):

  • P9 — Rebate now reaches household net income through no channel at all (TY2022–2023). After this PR, mt_property_tax_rebate's only consumer is the TAXSIM reporting aggregate, which feeds nothing in household_net_income. Per the 2023 instructions p.5 the rebate is real money (direct payment, up to $675/yr, income-tax-exempt); faithful modeling is a benefit-side transfer for those historical years. Removing the wrong channel first is correct — track the missing right channel as a follow-up.
  • P10 — 2024+ leakage into the TAXSIM aggregate. parameters/gov/states/mt/tax/income/credits/rebate/property/amount.yaml:3-4 has no sunset (comment says "only offered in the 2022 and 2023 tax years"), and parameters/gov/states/household/state_property_tax_credits.yaml still lists mt_property_tax_rebate at 2024/2025/2026 (lines 131, 156, 186) — a phantom $675 MT "property tax credit" in years the program no longer exists. Companion fix: add 2024-01-01: 0 and drop the 2024+ aggregate entries.
  • P11 — 2021 mt_income_tax_rebate likely carries the same misclassification (the 2023 instructions describe the HB 192 income tax rebate as "automatically issued", i.e. another standalone rebate; the 2021 Line-19 list does not name it). This is open PR #8970's territory — flag there rather than expanding this PR.

Should Address

(Actionable within this PR; none blocking.)

  • A1 — Refresh the dead mtrevenue.gov hrefs while the file is open (from references C1+S1). 4 of 5 cited hrefs 301→404 after the MT DOR site migration, including the one backing the edited 2022 entry. Verified working replacements at revenuefiles.mt.gov are supplied in pr9348-review-references.md (C1/S1 tables), with page anchors re-verified — note the 2022 anchor corrects #page=17#page=16 ("Line 19–Nonrefundable Credits" is on file p.16). While there: the 2025 reference title should name its section ("Schedule III – Tax Credits, Part I – Nonrefundable Credits") and line 10/13 trailing whitespace can be dropped.
  • A2 — Cite the removal itself in non_refundable.yaml (references S2). The "not a Form 2 credit" rationale lives only in the PR body and a test comment. Add the verified 2023 What's New citation (.../2023_Montana_Individual_Income_Tax_Return_Form_2_Instructions.pdf#page=5, "claimed via TransAction Portal or Form MPTR23... exempt from Montana income tax"). Do not add an MCA statute cite without verifying the section number (candidate 15-1-2302 unverified).
  • A3 — TY2022 is the untested half of the change (tests SA-1). The removed entry governed TY2022 and TY2023; only 2023 is tested. Add a period: 2022 sibling case asserting mt_property_tax_rebate: 675 and mt_non_refundable_credits: [0, 0, 0].
  • A4 — No end-to-end mt_income_tax assertion (tests SA-2, code SA-1, regulatory suggestion). The headline TaxAct-verified figure (3,683.16 → 5,708.16) is untested; a regression re-booking the rebate downstream of mt_non_refundable_credits would pass the new case. Add mt_income_tax: 5_708.16 to the issue-9347 case (run the model to confirm reproduction; the neighboring issue-9012 case already follows this pattern).
  • A5 — Nothing pins that the rebate was rerouted, not dropped (tests SA-3). Add an aggregate test (pattern exists at tests/.../gov/states/household/state_property_tax_credits/*_in_aggregate.yaml for vt/pa/nd/in): MT household, 2023, assert taxsim_state_property_tax_credit: 675.

Suggestions

  • S1 — New case uses state_fips: 30 while every other case in integration.yaml uses state_code: MT (lines 541, 563); the spm_units block is unnecessary for the asserted outputs. Cosmetic consistency.
  • S2 — No case covers the 2024-01-01 [] band of the non-refundable list (e.g. 2024 MT filer with capital gains → mt_non_refundable_credits: 0). Cheap guard on the third date band.
  • S3 — Pre-existing nits in tests/.../credits/rebate/mt_property_tax_rebate.yaml (untouched here): second case ("676 → 675") is mislabeled "Property tax less than rebate amount"; the exact boundary (675 → 675) is untested.
  • S4 — Pre-existing: mt_property_tax_rebate.py:13-19 models none of the statutory conditions (principal residence, 7-month ownership and occupancy, taxes billed and paid, claim filing) — worth a comment or follow-up if the rebate gains a benefit-side channel (P9).
  • S5 — Pre-existing: ma_mbta_enrolled_in_applicable_programs.py and tx_dart_reduced_fare_program_eligible.py use the Person-adds-group projection intentionally (boolean membership checks, never summed) — semantically correct today but fragile; a clarifying comment would inoculate them against the P1–P8 cleanup.

PDF Audit Summary

  • Scope adaptation: pdf-collector and pdf-audit were folded into the regulatory role.
  • 2 archived MT DOR Form 2 instruction PDFs (TY2022, TY2023) fetched from the Wayback Machine (captures 2025-04-14 / 2025-05-15, byte-identical to the originals), saved under RUN_ROOT, and quoted verbatim with #page= cites; the 2025 instructions verified at the live revenuefiles.mt.gov host.
  • Key audited facts: $675 lesser-of cap, TY2022/TY2023 only, separate claim (TAP/Form MPTR23), income-tax-exempt, and absence from both years' Nonrefundable Credits Schedules — all corroborated (5/5 references corroborate on content; 4/5 hrefs dead → A1).
  • The diff adds no #page= references (removal-only parameter edit + test + changelog), so the 5E page-anchor check is N/A; existing anchors were re-verified by the references role (one correction: 2022 → #page=16).

Validation Summary

Role Result
Regulatory (incl. PDF collect/audit) 0 CRITICAL — removal source-confirmed in both years' primary documents; tripling mechanism and 3,683.16 → 5,708.16 re-derived exactly
References 1 CRITICAL reported (dead 2022 href) — judged pre-existing link rot, content corroborated via archives; carried as A1 with verified replacement URLs
Code patterns 0 CRITICAL in the diff; 8 pre-existing sweep criticals (P1–P8); 9/10 pattern categories clean, 1 N/A
Tests 0 CRITICAL — both asserted values hand re-derived; case confirmed discriminating (pre-PR → [675, 675, 675])
Verification queue NONE — all cross-role questions settled in-queue; no EXT verification needed
Adjacency Open PR #8970 touches the same MT credit wiring (2021 income tax rebate) — different rebate, no file overlap, no semantic conflict; can merge in either order. P11 flagged to it.

Review Severity

APPROVE (posting mode: approve-or-request-changes per user instruction).
Judged on THIS diff: zero critical findings; the change is minimal, source-confirmed against primary documents for both affected years, regression-tested with a discriminating case, and CI-green. The 8 sweep criticals are pre-existing and outside the diff — follow-up issue material, not blockers. The should-address items (A1–A5) are non-blocking hardening that would fit naturally in this PR or an immediate follow-up.

Next Steps

  1. Merge-ready as-is; ideally fold in A1–A5 first (A1/A2 are copy-paste edits from the references report; A3–A5 are three small test cases).
  2. Open a tracking issue for the entity-projection bug class (P1–P8, file:line list above) — prioritize P1 (mt_misc_deductions, same MT subsystem) while the team is in this code.
  3. Open follow-ups for P9 (benefit-side channel for the TY2022–2023 rebate) and P10 (2024+ sunset + aggregate leakage).
  4. Flag P11 (2021 income tax rebate misclassification) on PR #8970 rather than expanding this PR.

Applies the Should-Address and Suggestion items from PavelMakarchuk's
2026-08-27 review. No substantive change to the removal; no parameter value
changed.

- A1: refresh dead mtrevenue.gov reference hrefs to live revenuefiles.mt.gov
  URLs (all verified HTTP 200), correct the 2022 anchor #page=17 -> #page=16,
  name the 2025 reference section, drop trailing whitespace.
- A2: cite the removal itself with the 2023 Form 2 What's New (p.5): the
  property tax rebate is claimed via TAP/Form MPTR23 and is income-tax-exempt,
  not a Form 2 nonrefundable credit.
- A3: add a period 2022 sibling case (the removed entry governed TY2022 too).
- A4: assert mt_income_tax 5,708.16 on the issue-9347 case (TaxAct-verified).
- A5: add an aggregate test pinning the rebate is rerouted to
  taxsim_state_property_tax_credit (675), not dropped.
- S1: use state_code MT and drop the unneeded spm_units block on the new case.
- S2: add a 2024 case covering the empty non-refundable list band.
- S3: relabel the mislabeled 676->675 rebate case and add the 675->675 boundary.
- S4: note the unmodeled statutory eligibility conditions on the rebate variable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YCwrSsGY7vPCpKYGfV1xRr
@DTrim99

DTrim99 commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

Review addressed — thanks @PavelMakarchuk

Applied all Should-Address (A1–A5) and Suggestion (S1–S4) items. No change to the substantive removal; no parameter value changed.

Should Address

  • A1 — refreshed the dead mtrevenue.gov reference hrefs to live revenuefiles.mt.gov URLs (each verified HTTP 200), corrected the 2022 anchor #page=17#page=16, named the 2025 reference section ("Schedule III – Tax Credits, Part I – Nonrefundable Credits"), and dropped the trailing whitespace.
  • A2 — cited the removal itself with the 2023 Form 2 "What's New" (p.5): the property tax rebate is claimed via the TransAction Portal / Form MPTR23 and is exempt from Montana income tax — not a Form 2 nonrefundable credit. (No MCA statute cite added, per your note.)
  • A3 — added a period: 2022 sibling case (the removed entry governed TY2022 as well as TY2023) asserting mt_property_tax_rebate: 675, mt_non_refundable_credits: [0, 0, 0].
  • A4 — added mt_income_tax: 5_708.16 to the issue-9347 case (the TaxAct-verified headline figure).
  • A5 — added an aggregate test (mt_property_tax_rebate_in_aggregate.yaml) pinning that the rebate is rerouted to taxsim_state_property_tax_credit (675), not dropped.

Suggestions

  • S1 — the new case now uses state_code: MT and drops the unnecessary spm_units block.
  • S2 — added a period: 2024 case covering the empty ([]) non-refundable list band.
  • S3 — relabeled the mislabeled "676 → 675" rebate case and added the exact 675 → 675 boundary.
  • S4 — noted the unmodeled statutory eligibility conditions (principal residence, 7-month ownership/occupancy, taxes billed & paid, claim filing) on the rebate variable.
  • S5 skipped — the clarifying comments on the unrelated ma_mbta_*/tx_dart_* files belong with the P1–P8 entity-projection cleanup, not this diff.

On the pre-existing findings (P1–P11): they're outside this diff, but the 8-instance Person-adds-group projection sweep (P1–P8) is worth a tracking issue — happy to open one (umbrella or per-instance), and to file P9/P10 (MT rebate benefit-side channel + 2024+ aggregate sunset). Just say the word.

I couldn't run the suite locally (broken 3.14-alpha venv), so the 5_708.16 and aggregate 675 values rely on CI to confirm.

Fixed with Claude Code assistance.

@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (724e795) to head (9792584).
⚠️ Report is 29 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #9348   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines           35        15   -20     
  Branches         2         0    -2     
=========================================
- Hits            35        15   -20     
Flag Coverage Δ
unittests 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Montana Property Tax Rebate wrongly reduces income tax and is multiplied by household size

2 participants